/**
 * <pre>
 * 提供公共的，独立的常用对话框功能，包括：错误，警告，提示，信息 和 成功 等类型的对话框
 * 依赖：
 *      jQuery              3.1.1
 *      bootstrap           3.3
 *      font-awesome        4.7.0
 *
 * 为全局变量 $ 增加一个属性 Alert 来提供对话框服务
 *
 * $.Alert.type (message[, escape][, when][, trigger])
 *
 * 其中：
 * type                     error, warn, prompt, info 或 success
 * message      required    消息内容，可以是 string, html 或 jquery 对象
 *                          当 string 或 html 类型时，直接显示
 *                          当 jquery 对象时，将该对象作为显示的元素显示在对话框中
 * escape       optional    指示是否转意 HTML 字符，如 `<`和`>`，默认 true
 * when         optional    字符串'after-close' 和 'before-close', 指示 trigger 在何时被执行，默认 'before-close'
 * trigger      optional    指示是否为正向（确定）按钮添加处理事件
 *
 * trigger 为一个处理函数：
 *      函数的 this 指针指向正向(确定)按钮本身。
 *      函数可接收一个参数 e, 它的 dialog 属性指向当前对话框对象。该对话框对象为 bootstrap 的 modal 类型.
 *</pre>
 */
(function ($) {
    // 界面上的显示字符串，可扩展或修改这些属性来提供多语言支持
    var R = {
        dialog:{
            title:{
                error:'alert.title.error', warn:'alert.title.warn',prompt:'alert.title.prompt',info:'alert.title.info',success:'alert.title.success'
                // error:RS(window.R,'alert.title.error'), warn:RS(window.R,'alert.title.warn'),prompt:RS(window.R,'alert.title.prompt'),info:RS(window.R,'alert.title.info'),success:RS(window.R,'alert.title.success')
            }
        },
        button:{ok:'alert.button.ok', cancel:'alert.button.cancel', yes:'alert.button.yes', no:'alert.button.no', save:'alert.button.save', 'roll-back':'alert.button.rollBack'}
        // button:{ok:RS(window.R,'alert.button.ok'), cancel:RS(window.R,'alert.button.cancel'), yes:RS(window.R,'alert.button.yes'), no:RS(window.R,'alert.button.no'), save:RS(window.R,'alert.button.save'), 'roll-back':RS(window.R,'alert.button.rollBack')}
    };
    if ($.Alert) return;
    $.Alert = (function ($) {
        // 界面显示的图标，font-awesome 的类名称
        var icons = {
            error:'times', warn:'exclamation', prompt:'question', info:'info', success:'check'
        },
        /** 全局缓存不同类型的对话框 */
        dialogs = {};

        /**
         * 实际的按钮处理程序
         */
        function handler () {
            var dialog = $(this).closest ('div.modal');
            if (dialog) {
                var context = dialog.data ('context');
                if (context) {
                    if (context.when === 'after-close') {
                        dialog.modal ('hide');
                    }
                    if (context.handler && typeof context.handler === 'function') {
                        if (false !== context.handler.apply (this, [{dialog:dialog}])) {
                            if (context.when !== 'after-close') {
                                dialog.modal ('hide');
                            }
                        }
                    }
                }
            }
        }

        /**
         * 当对话框关闭时的善后处理，删除无用的数据
         */
        function clear_handler () {
            var context = $(this).data ('context');
            if (context) {
                if ('handler' in context) {
                    delete context.handler;
                }
                if ('type' in context) {
                    delete context.type;
                }
            }
            $(this).removeData ('context');
        }

        /**
         * 转意 html 特殊字符
         * @param token 特殊字符
         * @returns {string}
         */
        function escape_html (token) {
            if (token === '<') {
                return '&lt;';
            } else if (token === '>') {
                return '&gt;';
            }
            return '';
        }

        /**
         * 显示消息框
         * @param type          消息框类型，必须是 `error`, `warn`, `prompt`, `info`和`success`中的一个.
         *                      当 type 为 `warn`或 `prompt`时，将多显示一个 `取消` 按钮
         * @param message       消息内容，可以是 string, html 或 jquery 对象
         * @param escape        指示是否转意 HTML 字符，如 `<`和`>`，默认 true
         * @param with_handler  指示是否为正向（确定）按钮添加处理事件。
         * @param context       运行环境
         */
        function show_message (type, message, escape, with_handler, context) {
            if (!(type in dialogs)) {
                build (type, with_handler);
            } else {
                var button = dialogs [type].dialog.find ('.btn.btn-primary');
                button.unbind ('click', handler);
                if (with_handler) {             // rebind click event.
                    button.bind ('click', handler);
                }
            }
            var dialog = dialogs [type];
            dialog.content.empty ();
            dialog.dialog.data ('context', context);

            if (typeof message === 'object' && ('$' in message)) {   // jquery object
                message.show ().appendTo (dialogs [type].content);
            } else {
                if (escape) {
                    dialog.content.append (message.replace (/([<>])/g, escape_html));
                } else if (message && (message[0] === '#' || message[0] === '.')) { // selectors
                    dialog.content.append ($(message).show ());
                } else {
                    dialog.content.append (message);
                }
            }
/*
            if (type in $.Alert.options) {
                var opt = $.Alert.options [type];
                if ('onshow' in opt && typeof opt ['onshow'] === 'function') {
                    dialog.dialog.on ('show.bs.modal', opt ['onshow']);
                }
                if ('onclose' in opt && typeof opt ['onclose'] === 'function') {
                    dialog.dialog.on ('hidden.bs.modal', opt ['onclose']);
                }
            }
*/
            dialog.dialog.modal ('show');
        }

        /**
         * 构建符合 bootstrap modal dialog 的 UI
         * @param type          对话框类型
         * @param with_handler  是否有处理函数
         */
        function build (type, with_handler) {
            // check whether the dialog created or not.
            if (type in dialogs) {
                return;
            }
            var root, header, footer, _body, btn;
            root = $('<div class="modal fade msg-dialog" role="dialog" tabindex="-1"/>')
                .addClass (type + '-box').appendTo ($(document.body));
            dialogs [type] = {dialog:root};
            root = $('<div class="modal-dialog"/>').appendTo (root);
            root = $('<div class="modal-content"/>').appendTo (root);

            header = $('<ul class="modal-header"/>').appendTo (root);
            $('<i class="fa fa-fw" />').addClass(type).addClass ('fa-' + icons [type] + '-circle').appendTo (
                $('<li/>').appendTo (header)
            );
            $('<li class="dlg-title"/>').addClass (type).text (RS (window.R, R.dialog.title [type])).appendTo (header);
            $('<a data-dismiss="modal"/>').html ('&times;').appendTo ($('<li/>').appendTo (header));

            _body = $('<div class="modal-body" />').appendTo (root);
            dialogs[type].content = $('<div class="dlg-content"/>').addClass (type).appendTo (_body);

            footer = $('<div class="modal-footer" />').appendTo (root);
            btn = $('<a class="btn btn-ok"/>').text (RS(window.R,'alert.button.ok')).appendTo (footer);

            if (with_handler) {
                btn.on ('click', handler);
                dialogs[type].dialog.on ('hidden.bs.modal', clear_handler);
            } else {
                btn.attr ('data-dismiss', 'modal');
            }

            // beforeshow and afterclose delegator
            dialogs[type].dialog.on ('show.bs.modal', function () {
                if (type in $.Alert.options) {
                    var opt = $.Alert.options [type];
                    if ('onshow' in opt && typeof opt ['onshow'] === 'function') {
                        opt ['onshow'].apply (dialogs[type].dialog, [{dialog: dialogs[type].dialog}]);
                    }
                }
            }).on ('hidden.bs.modal', function () {
                console.log ('execute anyway...');
                if (type in $.Alert.options) {
                    var opt = $.Alert.options [type];
                    if ('onclose' in opt && typeof opt ['onclose'] === 'function') {
                        opt ['onclose'].apply (dialogs[type].dialog, [{dialog: dialogs[type].dialog}]);
                    }
                }
            });
            
            if ('prompt' === type || 'warn' === type) {
                $('<a class="btn btn-cancel" data-dismiss="modal"/>').text (RS(window.R, R.button.cancel)).appendTo (footer);
            }
        }

        /**
         * wrap (type[, message[, escape[, trigger]]])
         * 整理参数的功能函数, 代理 {@link show_message} 函数
         */
        function wrap (type) {
            var message = arguments [1][0] || '', escape, trigger, a = arguments[1], t;
            var context = {type:type};
            if (undefined !== a[1]) {
                t = a[1];
                if (typeof t === 'boolean') {
                    escape = t;

                    t = a[2];
                    if (typeof t === 'string') {
                        context.when = t;
                    }

                    t = a[3];
                    if (typeof t === 'function') {
                        trigger = t;
                    }
                } else if (typeof t === 'string') {
                    escape = false;
                    context.when = t;

                    t = a[2];
                    if (typeof t === 'function') {
                        trigger = t;
                    }
                } else if (typeof t === 'function') {
                    escape = false;
                    trigger = t;
                }
            }
            if (trigger && typeof trigger === 'function') {
                // 缓存处理程序
                context.handler = trigger;
                show_message (type, message, escape, true, context);
            } else {
                show_message (type, message, escape, false, context);
            }
        }

        return {
            error   : function () { wrap ('error',   arguments); },
            info    : function () { wrap ('info',    arguments); },
            success : function () { wrap ('success', arguments); },
            warn    : function () { wrap ('warn',    arguments); },
            prompt  : function () { wrap ('prompt',  arguments); },
            options : {}
        };
    })($);
})(jQuery);